package com.actionsoft.bpms.server.fs.dc;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.compress.utils.IOUtils;

import com.actionsoft.apps.AppsConst;
import com.actionsoft.apps.lifecycle.api.AppsAPIManager;
import com.actionsoft.apps.resource.plugin.profile.DCPluginProfile;
import com.actionsoft.bpms.commons.mvc.view.ResponseObject;
import com.actionsoft.bpms.commons.security.processor.SecurityProcessorHelper;
import com.actionsoft.bpms.server.UserContext;
import com.actionsoft.bpms.server.conf.server.AWSServerConf;
import com.actionsoft.bpms.server.fs.DCContext;
import com.actionsoft.bpms.server.fs.FileProcessorEvent;
import com.actionsoft.bpms.server.fs.file.DCFileQueue;
import com.actionsoft.bpms.server.fs.file.ReadDCFile;
import com.actionsoft.bpms.server.fs.file.WriteDCFile;
import com.actionsoft.bpms.server.fs.file.dao.FileDao;
import com.actionsoft.bpms.server.fs.file.model.FileModel;
import com.actionsoft.bpms.util.AES;
import com.actionsoft.bpms.util.Base64;
import com.actionsoft.bpms.util.DBSql;
import com.actionsoft.bpms.util.MD5;
import com.actionsoft.bpms.util.UUIDGener;
import com.actionsoft.bpms.util.UtilFile;
import com.actionsoft.bpms.util.UtilString;
import com.actionsoft.exception.AWSObjectNotFindException;
import com.actionsoft.i18n.I18nRes;
import com.actionsoft.sdk.local.SDK;
import com.actionsoft.sdk.local.api.DCAPI;

/**
 * 操作DC的工具方法封装
 *
 * @author jack
 * @see DCContext DC上下文
 * @see DCAPI DC封装给开发者的常用API
 */
final public class DCUtil {

	private static DCUtil util = new DCUtil();

	/**
	 * 返回实例对象
	 *
	 * @return 实例对象
	 */
	public static DCUtil getInstance() {
		return util;
	}

	public static void setExtParam(DCContext dc, String key, Object v) {
		dc.getExtParams().put(key, v);
	}

	/**
	 * 造附件RepositoryName的工具方法
	 *
	 * @param name
	 * @param deepFile 是否四级算法存储
	 * @param encrypt 是否加密存储
	 * @param RWBytes 是否diy内容处理
	 * @return RepositoryName
	 */
	public static String genRepositoryName(String name, boolean deepFile, boolean encrypt, boolean RWBytes) {
		StringBuilder sb = new StringBuilder();
		if (encrypt) {
			sb.append(DCConst.RULE_PREFIX);
		}
		if (RWBytes) {
			sb.append(DCConst.RULE_PREFIX_JAVA_BYTES);
		}
		sb.append(name);
		if (deepFile) {
			sb.append(DCConst.RULE_SUFFIX);
		}
		return name;
	}

	/**
	 * 是否自定义DC内容处理，而非默认DC文件
	 *
	 * @param repositoryName 文档仓库根目录名
	 * @author jack
	 */
	public static boolean isDiyContent(String repositoryName) {
		return repositoryName != null && repositoryName.startsWith(DCConst.RULE_PREFIX_JAVA_BYTES);
	}

	/**
	 * 从ready事件后接管附件上传动作
	 *
	 * @param in 输入流
	 * @param context 文件上下文
	 * @param param 参数
	 * @throws Exception
	 * @author chengy
	 */
	public static boolean handlerWriteDCDefault(InputStream in, DCContext context, Map<String, Object> param) {
		String watchFileObj = context.getPath() + context.getFileName();
		// 追加到文件上传队列，监控！
		DCFileQueue.addWatch(watchFileObj, Thread.currentThread().getName());
		try {
			// 是否高安全存储要求
			if (context.isEncrypt()) {
				// -------------------
				// 执行加密前事件
				// -------------------
				// 通常在这里做知识库入库等操作，这时物理文件已存储完毕
				FileProcessorEvent.getInstance().handleUploadBeforeEncryptEvent(param, context.getDCProfile().getClazzName());
			}

			DCStoreUtil.create(context).write(in);
			if (context.getDCMessage() == null) {
				context.setDCMessage(DCMessage.OK, I18nRes.findValue(AppsConst.SYS_APP_PLATFORM, "文件已接收完毕"));
			}
			// -------------------
			// 执行success补偿事件
			// -------------------
			// 通常在这里做知识库入库等操作，这时物理文件已存储完毕
			FileProcessorEvent.getInstance().handleUploadSuccessEvent(param, context.getDCProfile().getClazzName());
			return true;
		} catch (Exception e) {
			e.printStackTrace(System.err);
			context.setDCMessage(DCMessage.ERROR, I18nRes.findValue(AppsConst.SYS_APP_PLATFORM, I18nRes.getUserLanguage(), "文件上传失败") + "," + I18nRes.findValue(AppsConst.SYS_APP_PLATFORM, I18nRes.getUserLanguage(), "原因是") + "[" + e.getMessage() + "]");
			// -------------------
			// 执行error补偿事件
			// -------------------
			FileProcessorEvent.getInstance().handleUploadErrorEvent(param, context.getDCProfile().getClazzName());
			return false;
		} finally {
			// 从文件上传监控队列释放
			DCFileQueue.removeWatch(watchFileObj);
		}
	}

	/**
	 * 云存储上传时忽略的RepositoryName
	 *
	 * @param context 文件上下文
	 * @return true/false
	 */
	public static boolean isIgnoreRepositoryName(DCContext context) {
		String repositoryName = context.getRepositoryName();
		if (UtilString.isEmpty(repositoryName)) {
			repositoryName = "";
		}
		if (repositoryName.equals(DCConst.REPOSITORY_APP_RESOURCE)) {
			return true;
		}
		if (repositoryName.equals(DCConst.REPOSITORY_PHOTO)) {
			return true;
		}
		if (repositoryName.equals(DCConst.REPOSITORY_TEMP)) {
			return true;
		}
		// 快邮不处理
		if (context != null && (("_CONTENT").equals(context.getFileName()) || ("_TRACK").equals(context.getFileName()))) {
			return true;
		}
		// 证书管理
		if (repositoryName.equals(DCConst.REPOSITORY_MOBILE_PORTAL)) {
			return true;
		}
		// 大文本不处理
		if (repositoryName.equals("-processbo-")) {
			return true;
		}
		// 流程变量字节流不处理
		if (repositoryName.equals(DCConst.REPOSITORY_PROCESS_VAR)) {
			return true;
		}
		// CC密钥库文件不处理
		if (repositoryName.equals(DCConst.REPOSITORY_CC)) {
			return true;
		}
		// // 金格office
		// if (repositoryName.equals("!iweboffice-")) {
		// return true;
		// }
		// // 金格pdf
		// if (repositoryName.equals("!iwebpdf-")) {
		// return true;
		// }
		// 电子印章
		if (repositoryName.equals("-cachet-")) {
			return true;
		}
		// 测试用例
		if (repositoryName.equals("testCase")) {
			return true;
		}
		// 测试用例临时文件
		if (repositoryName.equals("testCaseTmp")) {
			return true;
		}
		// 测试用例报告
		if (repositoryName.equals("report")) {
			return true;
		}
		// 文档预览转换的转换结果文件
		if (repositoryName.equals("-_transfer_onlinedoc-")) {
			return true;
		}
		// WPS OA助手模板
		if (repositoryName.equals("wpsOATemplate")) {
			return true;
		}
		// WPS OA助手
		String extParam = context.getExtParam();
		if ("wpsOA".equals(extParam)) {
			return true;
		}
		String ignoreRepositoryNames = SDK.getAppAPI().getProperty(AppsConst.SYS_APP_PLATFORM, "ignoreRepositoryNames");
		if (UtilString.isNotEmpty(ignoreRepositoryNames)) {
			List<String> strings = new UtilString(ignoreRepositoryNames).split(",");
			if (!UtilString.isEmpty(strings)) {
				if (strings.contains(repositoryName)) {
					return true;
				}
			}
		}
		// 文档生成
		if (repositoryName.equals("docgenerate")) {
			return true;
		}
		if (repositoryName.equals("documentgenerate")) {
			return true;
		}
		return false;
	}

	/**
	 * 是否需要高级别的安全存储，对该类文件正文和文件名进行加/解密处理
	 *
	 * @param repositoryName 文档仓库根目录名
	 * @return true/false
	 * @author jack
	 */
	public static boolean isHighSecurityStorage(String repositoryName) {
		if (repositoryName != null && repositoryName.startsWith(DCConst.RULE_PREFIX)) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 是否需要支持大容量4级结构的存储算法，采用该算法可以突破文件系统的单一目录文件数容量限制，理论可从原来存储3万至5万文件增容至3亿至5亿
	 *
	 * @param repositoryName 文档仓库根目录名
	 * @return true/false
	 * @author jack
	 */
	public static boolean isBigStorage(String repositoryName) {
		if (repositoryName != null && repositoryName.endsWith(DCConst.RULE_SUFFIX)) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 获得加/解密文件正文的key
	 *
	 * @return key
	 * @author jack
	 */
	public static String getSecurityKey(String path) {
		path = new UtilString(path).replace("\\", "/");
		String dir = path.substring(0, path.lastIndexOf("/"));
		return dir.substring(dir.lastIndexOf("/") + 1);
	}

	/**
	 * 根据指定字符编码加密文件名，后缀不变
	 *
	 * @param fileName 文件名
	 * @param charsetName 字符编码
	 * @return 加密后的文件名
	 */
	public static String encryptFileName(String fileName, String charsetName) {
		if (fileName == null || fileName.equals("")) {
			return fileName;
		}
		String newFileName = "";
		String tmpFileName = fileName;
		String fileSuffix = "";
		if (fileName.lastIndexOf(".") > -1) {
			tmpFileName = fileName.substring(0, fileName.lastIndexOf("."));
			fileSuffix = fileName.substring(fileName.lastIndexOf("."), fileName.length());
		}
		if (fileName.length() <= 50) {
			try {
				newFileName = new String(Base64.encode(AES.encrypt(tmpFileName.getBytes(charsetName), "awsfile")), charsetName) + fileSuffix;
				// 如果加密后出现/符号，则用!替换掉，解密时先替换!为/，然后解密
				if (newFileName.indexOf("/") != -1) {
					newFileName = new UtilString(newFileName).replace("/", "!");
				}
			} catch (Exception e) {
				// 加密失败
				newFileName = fileName;
			}
		} else {
			String key = new MD5().toDigest(fileName, "utf-8");
			Map<String, Object> param = new HashMap<>();
			param.put("ID", key);
			param.put("V", fileName);
			String id = DBSql.getString("SELECT ID FROM SYS_MD5_VALUE WHERE ID=:ID", "ID", param);
			if (UtilString.isEmpty(id)) {
				DBSql.update(DBSql.getInsertStatement("SYS_MD5_VALUE", param), param);
			}
			newFileName = key + fileSuffix;
		}
		return newFileName;
	}

	/**
	 * 加密文件名，后缀不变
	 *
	 * @param fileName 文件名
	 * @return 加密后的文件名
	 */
	public static String encryptFileName(String fileName) {
		if (fileName == null || fileName.equals("")) {
			return fileName;
		}
		String newFileName = "";
		String tmpFileName = fileName;
		String fileSuffix = "";
		if (fileName.lastIndexOf(".") > -1) {
			tmpFileName = fileName.substring(0, fileName.lastIndexOf("."));
			fileSuffix = fileName.substring(fileName.lastIndexOf("."), fileName.length());
		}
		if (fileName.length() <= 50) {
			try {
				newFileName = new String(Base64.encode(AES.encrypt(tmpFileName.toString().getBytes(), "awsfile"))) + fileSuffix;
				// 如果加密后出现/符号，则用!替换掉，解密时先替换!为/，然后解密
				if (newFileName.indexOf("/") != -1) {
					newFileName = new UtilString(newFileName).replace("/", "!");
				}
			} catch (Exception e) {
				// 加密失败
				newFileName = fileName;
			}
		} else {
			String key = new MD5().toDigest(fileName, "utf-8");
			Map<String, Object> param = new HashMap<>();
			param.put("ID", key);
			param.put("V", fileName);
			String id = DBSql.getString("SELECT ID FROM SYS_MD5_VALUE WHERE ID=:ID", "ID", param);
			if (UtilString.isEmpty(id)) {
				DBSql.update(DBSql.getInsertStatement("SYS_MD5_VALUE", param), param);
			}
			newFileName = key + fileSuffix;
		}
		return newFileName;
	}

	/**
	 * 解密文件名，后缀不变
	 *
	 * @param fileName 文件名
	 * @return 解密后的文件名
	 */
	public static String decryptFileName(String fileName) {
		if (fileName == null || fileName.equals("")) {
			return fileName;
		}
		String newFileName = "";
		String tmpFileName = "";
		String fileSuffix = "";
		if (fileName.lastIndexOf(".") > -1) {
			tmpFileName = fileName.substring(0, fileName.lastIndexOf("."));
			fileSuffix = fileName.substring(fileName.lastIndexOf("."), fileName.length());
		}
		if (fileName.length() <= 50) {
			// 首先判断文件名是否有!存在，存在则替换回原来的/，然后再进行解密操作
			if (tmpFileName.indexOf("!") != -1) {
				tmpFileName = new UtilString(tmpFileName).replace("!", "/");
			}
			try {
				newFileName = new String(AES.decrypt(Base64.decode(tmpFileName.getBytes()), "awsfile")) + fileSuffix;
			} catch (Exception e) {
				// 解密失败
				newFileName = fileName;
			}
		} else {
			String key = new MD5().toDigest(fileName, "utf-8");
			Map<String, Object> param = new HashMap<>();
			param.put("ID", key);
			String v = DBSql.getString("SELECT V FROM SYS_MD5_VALUE WHERE ID=:ID", "V", param);
			if (!UtilString.isEmpty(v)) {
				newFileName = v;
			} else {
				throw new AWSObjectNotFindException(I18nRes.findValue(AppsConst.SYS_APP_PLATFORM, "长文件名对应的字典") + "[" + key + "]" + I18nRes.findValue(AppsConst.SYS_APP_PLATFORM, "的值没有找到"));
			}

		}
		return newFileName;
	}

	/**
	 * 应用层不应该知道加解密细节，通过设置DCContext的
	 *
	 * @param context
	 * @return
	 */
	@Deprecated
	public static InputStream decryptFile(DCContext context) {
		try {
			return DCStoreUtil.read(context);
		} catch (Exception e) {
			context.setDCMessage(DCMessage.ERROR, I18nRes.findValue(AppsConst.SYS_APP_PLATFORM, "读附件发生错误") + "[" + e + "]");
			return null;
		}
	}

	/**
	 * 加密指定的文件
	 *
	 * @param context 上下文
	 * @return 加密后文件大小(单位k)
	 */
	public static int encryptFile(DCContext context) {
		String path = context.getPath() + context.getSecurityFileName();
		String password = getSecurityKey(path);
		int fileSize = 0;
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("password", password);
		params.put("path", path);
		fileSize = SecurityProcessorHelper.fireEncryptFile(params);
		return fileSize / 1024;
	}

	/**
	 * 获得一个临时文件路径的上下文声明（并不真实创建文件），如果路径不存在则建立文件夹。适用于为自己的App程序生成、处理临时文件， 该文件超过n天后会由AWS平台自动删除
	 *
	 * @param appId 应用id，数据将存于该应用下
	 * @param fileSuffix 临时文件名的后缀，如xls、jar，可以为null
	 * @return 构造一个DCContext对象, 如果给定的appId不存在返回null
	 * @author jack
	 */
	public static DCContext createTempFileContext(String appId, String fileSuffix) {
		return createTempFileContext(appId, null, null, fileSuffix);
	}

	/**
	 * 获得一个临时文件路径的上下文声明（并不真实创建文件），如果路径不存在则建立文件夹。适用于为自己的App程序生成、处理临时文件， 该文件超过n天后会由AWS平台自动删除
	 *
	 * @param appId 应用id，数据将存于该应用下
	 * @param groupValue 任意，临时目录的第1分类。不包含空格的英文字母，不建议包含怪字符，可以为null
	 * @param fileValue 任意，临时目录的第2分类。不包含空格的英文字母，不建议包含怪字符，可以为null
	 * @param fileSuffix 临时文件名的后缀，如xls、jar，可以为null
	 * @return 构造一个DCContext对象, 如果给定的appId不存在返回null
	 * @author jack
	 */
	public static DCContext createTempFileContext(String appId, String groupValue, String fileValue, String fileSuffix) {
		if (appId == null || appId.trim().length() == 0) {
			return null;
		}
		if (AppsAPIManager.getInstance().getAppContext(appId) == null) {
			return null;
		}
		if (groupValue == null || groupValue.equals(""))
			groupValue = "Normal";
		if (fileValue == null || fileValue.equals(""))
			fileValue = "Normal";
		if (fileSuffix == null)
			fileSuffix = "";
		if (fileSuffix.length() > 0)
			fileSuffix = "." + fileSuffix;
		String fileName = System.currentTimeMillis() + fileSuffix;
		DCContext context = new DCContext(null, DCProfileManager.getDCProfile(appId, DCConst.REPOSITORY_TEMP), appId, groupValue, fileValue, fileName);
		// 如果路径不存在
		File file = new File(context.getPath());
		if (!file.exists())
			file.mkdirs();
		return context;
	}

	/**
	 * 复制源文件至目标，如果目标对象未设置文件名，默认为源文件名
	 *
	 * @param sourceContext 要复制的文件对象上下文
	 * @param targetContext 目标，可以设置文件名也可忽略
	 * @return 成功返回true
	 * @author jack
	 */
	public static boolean copyDCFile(DCContext sourceContext, DCContext targetContext) {
		InputStream sourceFileByte = ReadDCFile.getInstance().read(sourceContext);
		// 如未指定目标文件名，默认源文件名
		if (targetContext.getFileName() == null || targetContext.getFileName().equals("")) {
			targetContext.setFileName(sourceContext.getFileName());
		}
		if (sourceContext != null && targetContext != null && !UtilString.isEmpty(sourceContext.getFileLength()) && UtilString.isEmpty(targetContext.getFileLength())) {
			targetContext.setFileLength(sourceContext.getFileLength());
		}
		try {
			return WriteDCFile.getInstance().write(sourceFileByte, targetContext);
		} finally {
			try {
				sourceFileByte.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 判断附件路径中某目录名称是否安全
	 *
	 * @param fileName 文件名
	 * @return true/false
	 */
	public static boolean isDangerFileName(String fileName) {
		return isDangerFileName(fileName, false);
	}

	/**
	 * 判断文件/文件夹名命名是否存在潜在危险
	 *
	 * @param fileName 文件夹/文件名
	 * @return 有高危险返回true
	 * @author jack
	 */
	public static boolean isDangerFileName(String fileName, boolean checkSuffix) {
		if (fileName == null) {
			return false;
		}

		if (checkSuffix) {
			String whitelist = SDK.getAppAPI().getProperty(AppsConst.SYS_APP_PLATFORM, "file.whitelist.suffix");
			String blacklist = SDK.getAppAPI().getProperty(AppsConst.SYS_APP_PLATFORM, "file.blacklist.suffix");
			if (!UtilString.isEmpty(whitelist)) {// 白名单后缀，例如：jpg|txt
				String[] ss = whitelist.split("\\|");
				if (fileName.lastIndexOf('.') != -1) {
					boolean safe = false;
					for (String s : ss) {
						if (fileName.substring(fileName.lastIndexOf('.') + 1).equalsIgnoreCase(s)) {
							safe = true;
							break;
						}
					}
					if (!safe) {
						return true;
					}
				}
			}
			if (!UtilString.isEmpty(blacklist)) {// 黑名单后缀，例如：exe|sh
				String[] ss = blacklist.split("\\|");
				if (fileName.lastIndexOf('.') != -1) {
					boolean safe = true;
					for (String s : ss) {
						if (fileName.substring(fileName.lastIndexOf('.') + 1).equalsIgnoreCase(s)) {
							safe = false;
							break;
						}
					}
					if (!safe) {
						return true;
					}
				}
			}
		}
		if (fileName.contains("..") || fileName.contains("..%2F") || fileName.contains("..\\") || fileName.contains("..%5C")) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 获取移动端的下载地址
	 *
	 * @param dcContext 文件上下文
	 * @return 下载地址
	 */
	public static String getMobileDownloadUrl(DCContext dcContext) {
		String downloadUrl = dcContext.getDownloadURL();
		downloadUrl = downloadUrl.substring(1, downloadUrl.length());
		if (downloadUrl.startsWith("/df")) {
			downloadUrl = SDK.getConfAPI().getMobileUrl() + "/r" + downloadUrl;
		} else if (downloadUrl.startsWith("./")) {
			downloadUrl = downloadUrl.substring(1, downloadUrl.length());
			downloadUrl = SDK.getConfAPI().getMobileUrl() + downloadUrl;
		}
		return downloadUrl;
	}

	/**
	 * 加密文件名（历史）
	 *
	 * @param fileName 文件名
	 * @return 加密后的文件名
	 */
	public static String encryptFileName_history(String fileName) {
		if ((fileName == null) || (fileName.equals(""))) {
			return fileName;
		}
		String newFileName = "";
		String tmpFileName = fileName;
		String fileSuffix = "";
		if (fileName.lastIndexOf(".") > -1) {
			tmpFileName = fileName.substring(0, fileName.lastIndexOf("."));
			fileSuffix = fileName.substring(fileName.lastIndexOf("."), fileName.length());
		}
		try {
			newFileName = new String(Base64.encode(AES.encrypt(tmpFileName.toString().getBytes(), "awsfile"))) + fileSuffix;

			if (newFileName.indexOf("/") != -1)
				newFileName = new UtilString(newFileName).replace("/", "!");
		} catch (Exception e) {
			newFileName = fileName;
		}
		return newFileName;
	}

	/**
	 * 解密文件名，后缀不变
	 *
	 * @param fileName 文件名
	 * @return 解密后的文件名
	 */
	public static String decryptFileName_history(String fileName) {
		if (fileName == null || fileName.equals("")) {
			return fileName;
		}
		String newFileName = "";
		String tmpFileName = "";
		String fileSuffix = "";
		if (fileName.lastIndexOf(".") > -1) {
			tmpFileName = fileName.substring(0, fileName.lastIndexOf("."));
			fileSuffix = fileName.substring(fileName.lastIndexOf("."), fileName.length());
		}
		// 首先判断文件名是否有!存在，存在则替换回原来的/，然后再进行解密操作
		if (tmpFileName.indexOf("!") != -1) {
			tmpFileName = new UtilString(tmpFileName).replace("!", "/");
		}
		System.out.println(tmpFileName);
		try {
			newFileName = new String(AES.decrypt(Base64.decode(tmpFileName.getBytes()), "awsfile")) + fileSuffix;
		} catch (Exception e) {
			// 解密失败
			newFileName = fileName;
		}
		return newFileName;
	}

	/**
	 * 云文档插入sys_files表
	 *
	 * @param context 文件上下文
	 * @param appId 应用id
	 * @param fileSize 文件大小
	 * @param cloudId 云存储id
	 * @param cloudAppId 云存储应用id
	 * @param cloudInfo 云存储信息
	 * @return id
	 */
	public static String writeSysFile(DCContext context, String appId, long fileSize, String cloudId, String cloudAppId, String cloudInfo) {
		FileDao fileDao = new FileDao();
		String id = UUIDGener.getUUID();
		FileModel fileModel = new FileModel();
		fileModel.setId(id);
		fileModel.setFileSize(fileSize + "");
		fileModel.setFileName(context.getFileName());
		fileModel.setCloudInfo(cloudInfo);
		fileModel.setCloud(true);
		fileModel.setPush(true);
		fileModel.setCloudId(cloudId);
		fileModel.setCloudAppId(cloudAppId);
		if (context.getSession() != null) {
			fileModel.setCreateUser(context.getSession().getUID());
		}
		fileModel.setGroupValue(context.getGroupValue());
		fileModel.setFileValue(context.getFileValue());
		fileModel.setRepositoryName(context.getRepositoryName());
		fileModel.setAppId(appId);
		fileDao.insert(fileModel);
		return id;
	}

	public static boolean existColdPath() {
		return !UtilString.isEmpty(getColdPath());
	}

	public static String getColdPath() {
		return AWSServerConf.getProperty("dc.coldPath");
	}

	public static String getPath() {
		return AWSServerConf.getProperty("dc.path");
	}

	/**
	 * 克隆输入流
	 *
	 * @param in 被克隆的流
	 * @return 克隆后的流
	 */
	public static InputStream cloneInputStream(InputStream in) {
		InputStream data = null;
		try {
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			byte[] buffer = new byte[1024];
			int len;
			while ((len = in.read(buffer)) > -1) {
				baos.write(buffer, 0, len);
			}
			baos.flush();
			data = new ByteArrayInputStream(baos.toByteArray());
			in.reset();
		} catch (IOException e) {

		}
		return data;
	}

	/**
	 * 打包下载一系列DC文件
	 *
	 * @param dcList 文件上下文集合
	 * @param zipFilePath 生成的zip路径
	 * @param zipFileName 生成的zip文件名称
	 * @return 下载信息json
	 */
	public static ResponseObject downloadPackage(UserContext me, List<DCContext> dcList, String zipFilePath, String zipFileName, String repositoryName) throws Exception {
		File targetFileDir = new File(zipFilePath);
		if (!targetFileDir.exists()) {
			targetFileDir.mkdirs();
		}
		try {
			for (DCContext dcContext : dcList) {
				// 获取文件流
				InputStream is = null;
				OutputStream out = null;
				try {
					File targetFile = new File(zipFilePath + dcContext.getFileName());// 名字不带版本号
					if (!targetFile.exists()) {
						targetFile.createNewFile();
					}
					out = new FileOutputStream(targetFile);
					is = ReadDCFile.getInstance().read(dcContext);
					IOUtils.copy(is, out);
					// is生成文件，放到指定位置
				} catch (Exception e) {
					e.printStackTrace();
				} finally {
					try {
						is.close();
						out.close();
					} catch (IOException e) {
						e.printStackTrace();
					}

				}
			}
			// 调用
			DCPluginProfile dcProfile = DCProfileManager.getDCProfile(AppsConst.SYS_APP_PLATFORM, repositoryName);
			DCContext zipDcContext = new DCContext(me, dcProfile, AppsConst.SYS_APP_PLATFORM, "zip", "rp", zipFileName);
			UtilFile.zipCompress(zipFilePath, new File(zipDcContext.getFilePath()));
			// 压缩文件
			String downloadURL = zipDcContext.getDownloadURL();
			return ResponseObject.newOkResponse(downloadURL);
		} catch (Exception e) {
			e.printStackTrace();
			return ResponseObject.newErrResponse(e.getMessage());
		}
	}

	public static void close(InputStream is) {
		if (is != null) {
			try {
				is.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}
